//
//  ViewController.m
//  MoboPlayerapp
//
//  Created by Kolyvan on 11.10.12.
//  Copyright (c) 2012 Konstantin Boukreev . All rights reserved.
//
//  https://github.com/kolyvan/MoboPlayer
//  this file is part of MoboPlayer
//  MoboPlayer is licenced under the LGPL v3, see lgpl-3.0.txt

#import "MoboSoftViewController.h"
#import <MediaPlayer/MediaPlayer.h>
#import <QuartzCore/QuartzCore.h>
#import "MoboPlayerDecoder.h"
#import "MoboAudioManager.h"
#import "MoboPlayerGLView.h"
#import "MoboLogger.h"

NSString * const MoboPlayerParameterMinBufferedDuration = @"MoboPlayerParameterMinBufferedDuration";
NSString * const MoboPlayerParameterMaxBufferedDuration = @"MoboPlayerParameterMaxBufferedDuration";
NSString * const MoboPlayerParameterDisableDeinterlacing = @"MoboPlayerParameterDisableDeinterlacing";

////////////////////////////////////////////////////////////////////////////////

static NSString * formatTimeInterval(CGFloat seconds, BOOL isLeft)
{
    seconds = MAX(0, seconds);
    
    NSInteger s = seconds;
    NSInteger m = s / 60;
    NSInteger h = m / 60;
    
    s = s % 60;
    m = m % 60;

    NSMutableString *format = [(isLeft && seconds >= 0.5 ? @"-" : @"") mutableCopy];
    if (h != 0) [format appendFormat:@"%ld:%0.2ld", (long)h, (long)m];
    else        [format appendFormat:@"%ld", (long)m];
    [format appendFormat:@":%0.2ld", (long)s];

    return format;
}

////////////////////////////////////////////////////////////////////////////////

enum {

    MoboPlayerInfoSectionGeneral,
    MoboPlayerInfoSectionVideo,
    MoboPlayerInfoSectionAudio,
    MoboPlayerInfoSectionSubtitles,
    MoboPlayerInfoSectionMetadata,    
    MoboPlayerInfoSectionCount,
};

enum {

    MoboPlayerInfoGeneralFormat,
    MoboPlayerInfoGeneralBitrate,
    MoboPlayerInfoGeneralCount,
};
////////////////////////////////////////////////////////////////////////////////
//static NSMutableDictionary * gHistory;

<<<<<<< HEAD
#define LOCAL_MIN_BUFFERED_DURATION   0.25
#define LOCAL_MAX_BUFFERED_DURATION   1.5
=======
#define LOCAL_MIN_BUFFERED_DURATION   0.3
#define LOCAL_MAX_BUFFERED_DURATION   2.5
>>>>>>> 3938e94d2c955167dabece781fdd852e5081ffa0
#define NETWORK_MIN_BUFFERED_DURATION 1.0
#define NETWORK_MAX_BUFFERED_DURATION 2.0

@interface MoboSoftViewController () {

    MoboPlayerDecoder      *_decoder;    
    dispatch_queue_t    _dispatchQueue;
    NSMutableArray      *_videoFrames;
    NSMutableArray      *_audioFrames;
    NSMutableArray      *_subtitles;
    NSData              *_currentAudioFrame;
    NSUInteger          _currentAudioFramePos;
    CGFloat             _moviePosition;
//    BOOL                _disableUpdateHUD;
    NSTimeInterval      _tickCorrectionTime;
    NSTimeInterval      _tickCorrectionPosition;
    NSUInteger          _tickCounter;
    BOOL                _fullscreen;
    float               history_postion;
//    float               player_speed;
//    BOOL                _hiddenHUD;
//    BOOL                _fitMode;
//    BOOL                _infoMode;
    NSInteger            _reservedframenum;
    BOOL                _restoreIdleTimer;
    BOOL                _interrupted;
    MoboPlayerGLView       *_glView;
    UIImageView         *_imageView;

  //  UIActivityIndicatorView *_activityIndicatorView;
    NSMutableArray      * _Nssubtitleslabel;
    NSInteger            _SubtitleFontSize;
    UIColor                 *_SubtitleisShadow;
    UIColor              *_SubtitleTextColor;
    
    BOOL             _issubtitletextbold;                  //粗体
    BOOL                _issubtitleitalic ;                 //斜体
    
//    UILabel             *_subtitlesLabel;
    CGFloat             _bufferedDuration;
    CGFloat             _minBufferedDuration;
    CGFloat             _maxBufferedDuration;
    BOOL                _buffered;
    
//    BOOL                _savedIdleTimer;
    
    NSMutableArray            *_subtitleString;
//    NSDictionary        *_parameters;
    UIImage             *image;
    float               _addorsubtime ;                 //字幕时间轴加减时间；
}

//@property (readwrite) BOOL playing;
@property (readwrite) BOOL decoding;
@property (readwrite, strong) MoboArtworkFrame *artworkFrame;
@end


@implementation MoboSoftViewController
@synthesize moboScalingMode = _moboScalingMode;
//+ (void)initialize
//{
////    if (!gHistory)
////        gHistory = [NSMutableDictionary dictionary];
//}


+ (id) movieViewControllerWithContentPath: (NSString *) path
                               parameters: (NSDictionary *) parameters
{    
    id<MoboAudioManager> audioManager = [MoboAudioManager audioManager];
   [audioManager activateAudioSession];
    return [[MoboSoftViewController alloc] initWithContentPath: path parameters: parameters];
}

- (id) initWithContentPath: (NSString *) path
                parameters: (NSDictionary *) parameters
{
    NSAssert(path.length > 0, @"empty path");
    
 //   self = [super initWithNibName:nil bundle:nil];
    self = [super init];
    if (self) {
        
        _moviePosition = 0;
        
        __weak MoboSoftViewController *weakSelf = self;
        
        MoboPlayerDecoder *decoder = [[MoboPlayerDecoder alloc] init];
        
        decoder.interruptCallback = ^BOOL(){
            
            __strong MoboSoftViewController *strongSelf = weakSelf;
            return strongSelf ? [strongSelf interruptDecoder] : YES;
        };
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
            NSError *error = nil;
            [decoder openFile:path error:&error];
                        
            __strong MoboSoftViewController *strongSelf = weakSelf;
            if (strongSelf) {
                
                dispatch_sync(dispatch_get_main_queue(), ^{
                    
                    [strongSelf setMovieDecoder:decoder withError:error];                    
                });
            }
        });
    }
    return self;
}

- (void) dealloc
{
    [self pause];
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    if (_dispatchQueue) {
        // Not needed as of ARC.
//        dispatch_release(_dispatchQueue);
        _dispatchQueue = NULL;
    }
//    if (_glView) {
//        [_glView removeFromSuperview] ;
//    }
    
    LoggerStream(1, @"%@ dealloc", self);
}

- (void)loadView
{
    
    CGRect bounds = [[UIScreen mainScreen] bounds];
    self.view = [[UIView alloc] initWithFrame:bounds];
    self.view.backgroundColor = [UIColor blackColor];
    self.view.tintColor = [UIColor blackColor];

//    _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhiteLarge];
//    _activityIndicatorView.center = self.view.center;
//    _activityIndicatorView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
//    
//    [self.view addSubview:_activityIndicatorView];
    
    
    _Nssubtitleslabel = [NSMutableArray array];
    _SubtitleFontSize =20;
    UILabel *lastLabel;
    for (int i=0; i<10; i++) {
        
        UILabel * _subtitlesLabel;
        _subtitlesLabel = [[UILabel alloc] init];
        _subtitlesLabel.numberOfLines = 0;
        _subtitlesLabel.backgroundColor = [UIColor clearColor];
        _subtitlesLabel.adjustsFontSizeToFitWidth = NO;
        _subtitlesLabel.textAlignment = NSTextAlignmentCenter;
        _subtitlesLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        _subtitlesLabel.hidden = YES;
        
        [_subtitlesLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
        [self.view addSubview:_subtitlesLabel];
        
        NSLayoutConstraint *constraint;
        constraint = [NSLayoutConstraint constraintWithItem:_subtitlesLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
        [self.view addConstraint:constraint];
        if (i == 0) {
            constraint = [NSLayoutConstraint constraintWithItem:_subtitlesLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:10];
        }else{
            constraint = [NSLayoutConstraint constraintWithItem:_subtitlesLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:lastLabel attribute:NSLayoutAttributeTop multiplier:1 constant:0];
        }
        [self.view addConstraint:constraint];
        constraint = [NSLayoutConstraint constraintWithItem:_subtitlesLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
        [self.view addConstraint:constraint];
        
        [_Nssubtitleslabel addObject:_subtitlesLabel];
        lastLabel = _subtitlesLabel;
    }
    if (_decoder) {
        
        [self setupPresentView];
        
    }
}

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    _SubtitleTextColor = [UIColor whiteColor];
    if (self.presentingViewController)
        [self fullscreenMode:YES];
    
//    _savedIdleTimer = [[UIApplication sharedApplication] isIdleTimerDisabled];
    
    if (_decoder) {
        
        [self restorePlay];
        
    } else {

//        [_activityIndicatorView startAnimating];
    }
    _interrupted = NO;
    
}

- (void) viewWillDisappear:(BOOL)animated
{    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    [super viewWillDisappear:animated];
    
    
    if (_decoder) {
        [self pause];
    }
    
    if (_fullscreen)
        [self fullscreenMode:NO];
        
//    [[UIApplication sharedApplication] setIdleTimerDisabled:_savedIdleTimer];
    
//    [_activityIndicatorView stopAnimating];
    _buffered = NO;
    _interrupted = YES;
    LoggerStream(1, @"viewWillDisappear softview %@", self);
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

- (void) applicationWillResignActive: (NSNotification *)notification
{
//    [self showHUD:false];
    [self pause];
    
    LoggerStream(1, @"applicationWillResignActive");
}

#pragma mark - public

-(void) play
{
    if (self.playing)
        return;
    if (!_decoder.validVideo &&
        !_decoder.validAudio) {
        return;
    }

    if (_interrupted)
        return;
    self.playing = YES;
    _interrupted = NO;
    _tickCorrectionTime = 0;
    _tickCounter = 0;
    [self asyncDecodeFrames];
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0 * NSEC_PER_SEC);
   // NSLog(@"dispatch_time_t:%llu",popTime);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [self tick];
    });

    if (_decoder.validAudio)
        [self enableAudio:YES];

    LoggerStream(1, @"play movie");
}

- (void) pause
{
    if (!self.playing)
        return;
    self.playing = NO;

    [self enableAudio:NO];
    LoggerStream(1, @"pause movie");
}
-(void) sethistoryposyion:(float) num
{
    history_postion = num;
}
- (void) seekToTime: (CGFloat) position;
{
    [self setMoviePosition: position ];
}
- (BOOL) hasSubtitle
{
    return _decoder.validSubtitles;
}
- (NSUInteger) getSubtitleCount
{
    return _decoder.subtitleStreamsCount;
}
- (NSArray *) selectedSubtitleStream
{
    return _decoder.selectedSubtitleStreams;
}
- (BOOL) setSelectedSubtitleStream:(NSArray *)selected
{
    
    for (int n =0; n<_Nssubtitleslabel.count;n++) {
        
        UILabel * _subtitlesLabel = _Nssubtitleslabel[n];
        _subtitlesLabel.text = @"";
    }
    
    return  [_decoder setSelectedSubtitleStream:selected];
}
-(BOOL ) AddSubtitleFile: (NSString *) path
                Filename:(NSString *)name;
{
    BOOL isok=  [_decoder AddSubtitleFile:path Filename:name];
   return isok;
}
- (NSArray *) GetSubtitleNSArray
{
    return _decoder.subtitleStreamsNsArray;
}
- (NSArray *) AudioStreamNSArray
{
    return _decoder.audioStreamsNSArray;
}
- (NSInteger) selectedAudioStream
{
    return _decoder.selectedAudioStream;
}
- (void) setSelectedAudioStream:(NSInteger)selected
{
    [_decoder setSelectedAudioStream:selected];
}
- (NSUInteger) getAudioCount
{
    return _decoder.audioStreamsCount;
}
- (BOOL) isPlaying
{
    return self.playing;
}
- (CGFloat) getFullTime
{
    return  _decoder.duration;
} 
- (CGFloat) getCurrentTime
{
<<<<<<< HEAD
    if (_Player_Speed != 1.0&&_reservedframenum<=0) {
=======
    if (_Player_Speed != 1.0) {
>>>>>>> 3938e94d2c955167dabece781fdd852e5081ffa0
        CGFloat  time=_moviePosition*_Player_Speed;
        if (time >_decoder.duration) {
            return    _moviePosition;
        }
        return time;
    }
    return _moviePosition;
}
- (void) stop
{
    if (_fullscreen)
        [self fullscreenMode:NO];
//    [_activityIndicatorView stopAnimating];
    _buffered = NO;
    _interrupted = YES;
    
    if (self.playing)
    {
        self.playing = NO;
        [self enableAudio:NO];
    }
    if (_dispatchQueue) {
        dispatch_barrier_async(_dispatchQueue, ^{
           
            [self freeBufferedFrames];
            [_decoder closeFile];
            _decoder = nil;            
        });
    }

}
-(UIImage *) SaveScreenShot:(NSInteger) pwidth height:(NSInteger) pheight;
{
        if(_imageView)
            return _imageView.image;
         return [_decoder savepicture:pwidth height:pheight];

}
-(NSDictionary *) getStreamNSinfo
{
    return _decoder.streaminfo;
}

- (BOOL) isBufferring
{
    return _buffered;
}
- (CGFloat) getBufferPercent
{
    return _bufferedDuration / _minBufferedDuration;
}
-(void) SetSubtitleProperty:(NSInteger) fontsize
                Shadowcolor:(UIColor*) shadowcolor        //阴影 clearcolor is none
                  TextColor:(UIColor*) textcolor
                 istextbold:(BOOL) bold                  //粗体
                     italic:(BOOL) italic                //斜体
               AddorSubtime:(float) time
                  alignment:(NSInteger) alinum          // 0:center  1:left  2:right
             bottomdistance:(NSInteger) bottomdistance;  //地边距
{
    
    _SubtitleFontSize = fontsize;
    _SubtitleisShadow = shadowcolor;
    _SubtitleTextColor =textcolor;
    _issubtitletextbold =bold;
    _issubtitleitalic =italic;
    _addorsubtime = time;
    
    UILabel* lastLabel;
    for (int n =0; n<10;n++) {
        
        UILabel * _subtitlesLabel = _Nssubtitleslabel[n];

        _subtitlesLabel.textColor =_SubtitleTextColor;
        switch (alinum) {
            case 0:
                _subtitlesLabel.textAlignment =NSTextAlignmentCenter;
                break;
            case 1:
                _subtitlesLabel.textAlignment =NSTextAlignmentLeft;
                break;
            case 2:
                _subtitlesLabel.textAlignment =NSTextAlignmentRight;
                break;
            default:
                 _subtitlesLabel.textAlignment =NSTextAlignmentCenter;
                break;
        }

        _subtitlesLabel.shadowColor = _SubtitleisShadow;
        _subtitlesLabel.shadowOffset =CGSizeMake(1.0, 1.0);
        if(_issubtitletextbold)
            [_subtitlesLabel setFont:[UIFont boldSystemFontOfSize:_SubtitleFontSize]];
        else
            [_subtitlesLabel setFont:[UIFont systemFontOfSize:_SubtitleFontSize]];
        _subtitlesLabel.hidden = NO;
    
    
        NSLayoutConstraint *constraint;
        constraint = [NSLayoutConstraint constraintWithItem:_subtitlesLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
        [self.view addConstraint:constraint];
        if (n == 0) {
            constraint = [NSLayoutConstraint constraintWithItem:_subtitlesLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:bottomdistance*-20];
        }else{
            constraint = [NSLayoutConstraint constraintWithItem:_subtitlesLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:lastLabel attribute:NSLayoutAttributeTop multiplier:1 constant:0];
        }
        [self.view addConstraint:constraint];
        constraint = [NSLayoutConstraint constraintWithItem:_subtitlesLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
        [self.view addConstraint:constraint];
        lastLabel = _subtitlesLabel;
    }
    
    
}

- (void) setMoviePosition: (CGFloat) position
{
    NSLog(@" seek to position :%.4f",position);
    BOOL playMode = self.playing;
    
    self.playing = NO;
    [self enableAudio:NO];
    
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

        [self updatePosition:position playMode:playMode];
    });
}

- (void) restorePlay
{
    if (history_postion -0>0.00001)
        [self updatePosition:history_postion playMode:YES];
    else
        [self play];
}


#pragma mark - private

- (void) setMovieDecoder: (MoboPlayerDecoder *) decoder
               withError: (NSError *) error
{
    LoggerStream(2, @"setMovieDecoder");
            
    if (!error && decoder) {
        
        _decoder        = decoder;
//        _dispatchQueue  = dispatch_queue_create("MoboPlayer", DISPATCH_QUEUE_SERIAL);
        _dispatchQueue  = dispatch_queue_create("MoboPlayer", DISPATCH_QUEUE_CONCURRENT);
        _videoFrames    = [NSMutableArray array];
        _audioFrames    = [NSMutableArray array];
        _subtitles = [NSMutableArray array];
        if (_decoder.isNetwork) {
            
            _minBufferedDuration = NETWORK_MIN_BUFFERED_DURATION;
            _maxBufferedDuration = NETWORK_MAX_BUFFERED_DURATION;
            
        } else {
            _minBufferedDuration = LOCAL_MIN_BUFFERED_DURATION;
            _maxBufferedDuration = LOCAL_MAX_BUFFERED_DURATION;
        }
        
        if (!_decoder.validVideo)
            _minBufferedDuration *= 10.0; // increase for audio
        
        LoggerStream(2, @"buffered limit: %.1f - %.1f", _minBufferedDuration, _maxBufferedDuration);
        
        if (self.isViewLoaded) {
            
            [self setupPresentView];
            [self restorePlay];
        }
        
    } else {
        
         if (self.isViewLoaded && self.view.window) {
        
//             [_activityIndicatorView stopAnimating];
             if (!_interrupted)
                 [self handleDecoderMovieError: error];
         }
    }
}

- (void) setupPresentView
{
    CGRect bounds = self.view.bounds;
    
    if (_decoder.validVideo) {

            _glView = [[MoboPlayerGLView alloc] initWithFrame:bounds decoder:_decoder];
    } 
    
    if (!_glView) {
        
        NSLog(@"fallback to use RGB video frame and UIKit");
        [_decoder setupVideoFrameFormat:MoboVideoFrameFormatRGB];
        _imageView = [[UIImageView alloc] initWithFrame:bounds];
        _imageView.backgroundColor = [UIColor blackColor];
    }
    
    UIView *frameView = [self frameView];
    frameView.contentMode = UIViewContentModeScaleAspectFit;
    frameView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    
    [self.view insertSubview:frameView atIndex:0];
    
   if (!_decoder.validVideo) {
       
        _imageView.image = [UIImage imageNamed:@"icon_music"];
        _imageView.contentMode =UIViewContentModeScaleAspectFit;
    }
    
    self.view.backgroundColor = [UIColor clearColor];
    
    
    NSArray * a = [[NSArray alloc]initWithObjects:@0,nil];
    
    [_decoder setSelectedSubtitleStream: a];
 
}
- (UIView *) frameView
{
    return _glView ? _glView : _imageView;
}
/*
 outdata:
 numFrames: 当前已解码，并未播放部分
 numchannels:通道数目
*/


- (void) audioCallbackFillData: (float *) outData
                     numFrames: (UInt32) numFrames
                   numChannels: (UInt32) numChannels
{
    //fillSignalF(outData,numFrames,numChannels);
    //return;

//    if (_buffered) {
//        memset(outData, 0, numFrames * numChannels * sizeof(float));
//        return;
//    }

    @autoreleasepool {
        
        while (numFrames > 0)
        {
            
            if (!_currentAudioFrame) {
                
                @synchronized(_audioFrames) {
                    
                    NSUInteger count = _audioFrames.count;
                    
                    if (count > 0)
                    {
                        
                        MoboAudioFrame *frame = _audioFrames[0];

#ifdef DUMP_AUDIO_DATA
                        LoggerAudio(2, @"Audio frame position: %f", frame.position);
#endif
                        if (_decoder.validVideo)
                        {
                        
                            const CGFloat delta = _moviePosition - frame.position;       //当前播放进度，待播放frame之间的时间差
                            
                            if (delta < -0.1) {
                                
                                memset(outData, 0, numFrames * numChannels * sizeof(float));
//#ifdef DEBUG
<<<<<<< HEAD
//                                NSLog(@"waitting audio frame _moviePosition, frame.position frame.duration %.4f,%.4f,%.4f",_moviePosition,frame.position,frame.duration);
=======
//                                NSLog(@"===waitting audio frame _moviePosition, frame.position frame.duration %.4f,%.4f,%.4f",_moviePosition,frame.position,frame.duration);
>>>>>>> 3938e94d2c955167dabece781fdd852e5081ffa0
//#endif
                                break; // silence and exit
                            }
                            
                            [_audioFrames removeObjectAtIndex:0];
                            
<<<<<<< HEAD
                            if (delta > 1.5 && count > 1) {
=======
                            if (delta > 0.3 && count > 1) {
>>>>>>> 3938e94d2c955167dabece781fdd852e5081ffa0
#if  1
                                
                                NSLog(@"skip audio frame _moviePosition, frame.position frame.duration %.4f,%.4f,%.4f",_moviePosition,frame.position,frame.duration);
#endif
                                continue;
                            }
                            
                            
                        } else {
                            [_audioFrames removeObjectAtIndex:0];
                            _moviePosition = frame.position;
                            _bufferedDuration -= frame.duration;
                        }
                        
                        _currentAudioFramePos = 0;
                        _currentAudioFrame = frame.samples;
                        
                    }
                }
            }
            
            if (_currentAudioFrame) {
                
                const void *bytes = (Byte *)_currentAudioFrame.bytes + _currentAudioFramePos;
                const NSUInteger bytesLeft = (_currentAudioFrame.length - _currentAudioFramePos);
                const NSUInteger frameSizeOf = numChannels * sizeof(float);
                const NSUInteger bytesToCopy = MIN(numFrames * frameSizeOf, bytesLeft);
                const NSUInteger framesToCopy = bytesToCopy / frameSizeOf;
                
                memcpy(outData, bytes, bytesToCopy);
                numFrames -= framesToCopy;
                outData += framesToCopy * numChannels;
//                NSLog(@"numChannels     %d",numChannels);
                if (bytesToCopy < bytesLeft)
                    _currentAudioFramePos += bytesToCopy;
                else
                    _currentAudioFrame = nil;                
                
            } else
            {
                
                memset(outData, 0, numFrames * numChannels * sizeof(float));
                //LoggerStream(1, @"silence audio");

                
                break;
            }
        }
    }
}

- (void) enableAudio: (BOOL) on
{
    id<MoboAudioManager> audioManager = [MoboAudioManager audioManager];

    
    if (on && _decoder.validAudio) {
                
        audioManager.outputBlock = ^(float *outData, UInt32 numFrames, UInt32 numChannels) {
            
            [self audioCallbackFillData: outData numFrames:numFrames numChannels:numChannels];
        };
        
        [audioManager play];
        
        LoggerAudio(2, @"audio device smr: %d fmt: %d chn: %d",
                    (int)audioManager.samplingRate,
                    (int)audioManager.numBytesPerSample,
                    (int)audioManager.numOutputChannels);
    } else {
        
        [audioManager pause];
        audioManager.outputBlock = nil;
    }
}

- (BOOL) addFrames: (NSArray *)frames
{
    if (_decoder.validVideo) {
        
        @synchronized(_videoFrames) {
            
            for (MoboPlayerFrame *frame in frames)
                if (frame.type == MoboPlayerFrameTypeVideo) {
                    [_videoFrames addObject:frame];
                    _bufferedDuration += frame.duration;
                }
        }
    }
    
    if (_decoder.validAudio) {
        
        @synchronized(_audioFrames) {
            
            for (MoboPlayerFrame *frame in frames)
                if (frame.type == MoboPlayerFrameTypeAudio) {
                    [_audioFrames addObject:frame];
                    if (!_decoder.validVideo)
                        _bufferedDuration += frame.duration;
                }
        }
        
        if (!_decoder.validVideo) {
            
            for (MoboPlayerFrame *frame in frames)
                if (frame.type == MoboPlayerFrameTypeArtwork)
                    self.artworkFrame = (MoboArtworkFrame *)frame;
        }
    }
    
    if (_decoder.validSubtitles) {
        
        @synchronized(_subtitles) {
            
            for (MoboPlayerFrame *frame in frames)
                if (frame.type == MoboPlayerFrameTypeSubtitle) {
                  //   NSLog(@"subtitle  %@",frame);
                    [_subtitles addObject:frame];
                }
        }
    }
    
    return self.playing && _bufferedDuration < _maxBufferedDuration;
}

- (BOOL) decodeFrames
{
    //NSAssert(dispatch_get_current_queue() == _dispatchQueue, @"bugcheck");
    
    NSArray *frames = nil;
    
    if (_decoder.validVideo ||
        _decoder.validAudio) {
        frames = [_decoder decodeFrames:0.03];
    }
    
    if (frames.count) {
        return [self addFrames: frames];
    }
    return NO;
}

- (void) asyncDecodeFrames
{
    if (self.decoding)
        return;
    
    __weak MoboSoftViewController *weakSelf = self;
    __weak MoboPlayerDecoder *weakDecoder = _decoder;
    
    const CGFloat duration = _decoder.isNetwork ? 1.0f : 0.03f;
    
    self.decoding = YES;
    dispatch_async(_dispatchQueue, ^{
        
        {
            __strong MoboSoftViewController *strongSelf = weakSelf;
            if (!strongSelf.playing)
                return;
        }
        
        BOOL good = YES;
        while (good) {
            
            good = NO;
            
            @autoreleasepool {
                
                __strong MoboPlayerDecoder *decoder = weakDecoder;
                
                if (decoder && (decoder.validVideo || decoder.validAudio))
                {
                    
                    NSArray *frames = [decoder decodeFrames:duration];
                    if (frames.count)
                    {
                        __strong MoboSoftViewController *strongSelf = weakSelf;
                        if (strongSelf)
                            good = [strongSelf addFrames:frames];
                    }
                }
            }
        }
        {
            self.decoding =false;
        }
    });
}


-(void) setMoboPlayer_speed:(float) player_speed
{
<<<<<<< HEAD
    if(player_speed <=0.5)
        player_speed=0.5;
    _Player_Speed = player_speed;
    [_decoder setspeedfilter:_Player_Speed];
//    if(_Player_Speed!=1.0)
//    {
//        CGFloat num = [self getCurrentTime];
//        [self setMoviePosition:num];
//    }
//    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC);
//    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//    
//    });
    
    _reservedframenum =_videoFrames.count;

//    _bufferedDuration = 0;
    @synchronized(_audioFrames) {
        
        [_audioFrames removeAllObjects];
        _currentAudioFrame = nil;
    }
    if (_subtitles) {
        @synchronized(_subtitles) {
            [_subtitles removeAllObjects];
        }
    }    
=======
    _Player_Speed = player_speed;
    _decoder.playerspeed =player_speed;
    NSLog(@" speeed  %f",_Player_Speed);
>>>>>>> 3938e94d2c955167dabece781fdd852e5081ffa0
}

- (void) tick
{
    if (_buffered && ((_bufferedDuration > _minBufferedDuration) || _decoder.isEOF)) {
        
        _tickCorrectionTime = 0;
        _buffered = NO;
//        [_activityIndicatorView stopAnimating];        
    }
    
    CGFloat interval = 0;
    if (!_buffered)
        interval = [self presentFrame] ;
    if (self.playing) {
        
        const NSUInteger leftFrames =  (_decoder.validVideo ? _videoFrames.count : 0) + (_decoder.validAudio ? _audioFrames.count : 0);
        
        if (0 == leftFrames) {
            
            if (_decoder.isEOF) {
                
                [self pause];
                return;
            }
            
            if (_minBufferedDuration > 0 && !_buffered) {
                                
                _buffered = YES;
//                [_activityIndicatorView startAnimating];
            }
        }
        
        if (!leftFrames || !(_bufferedDuration > _minBufferedDuration)) {
            
            [self asyncDecodeFrames];
        }
        
        
        const NSTimeInterval correction = (interval+[self tickCorrection]);

        const NSTimeInterval time = MAX(correction, 0.01);
       
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, time * NSEC_PER_SEC);
//        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [self tick];
        });
    }
    
//    if ((_tickCounter++ % 3) == 0) {
//        [self updateHUD];
//    }
}

- (CGFloat) tickCorrection
{
    if (_buffered)
        return 0;
    
    const NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
    
    if (!_tickCorrectionTime) {
        
        _tickCorrectionTime = now;
        _tickCorrectionPosition = _moviePosition;
        return 0;
    }
    
    NSTimeInterval dPosition = _moviePosition - _tickCorrectionPosition;
    NSTimeInterval dTime = now - _tickCorrectionTime;
    NSTimeInterval correction = dPosition - dTime;
    
    if (correction > 1.f || correction < -1.f) {
        
     //   LoggerStream(1, @"tick correction reset %.2f", correction);
        correction = 0;
        _tickCorrectionTime = 0;
    }
    
    return correction;
}

- (CGFloat) presentFrame
{
    CGFloat interval = 0;
    
    if (_decoder.validVideo) {
        
        MoboVideoFrame *frame;
        
        @synchronized(_videoFrames) {
            
            if (_videoFrames.count > 0) {
                
                frame = _videoFrames[0];
                [_videoFrames removeObjectAtIndex:0];
                if (_reservedframenum>0) {
                    _reservedframenum --;
                }
                
                _bufferedDuration -= frame.duration;
            }
        }
        if (frame)
            interval = [self presentVideoFrame:frame];
        
    } else if (_decoder.validAudio) {
        if (self.artworkFrame) {
            
            _imageView.image = [self.artworkFrame asImage];

            self.artworkFrame = nil;
        }
    }
    if (_decoder.validSubtitles)
        [self presentSubtitles];
    return interval;
}

- (CGFloat) presentVideoFrame: (MoboVideoFrame *) frame
{
    if (_glView) {
        
        [_glView render:frame];
        
    } else {
        
        MoboVideoFrameRGB *rgbFrame = (MoboVideoFrameRGB *)frame;
        _imageView.image = [rgbFrame asImage];
    }
    
    _moviePosition = frame.position;
        
    return frame.duration;
}

- (void) presentSubtitles
{
    NSArray *actual, *outdated;
    
    if ([self subtitleForPosition:_moviePosition  actual:&actual  outdated:&outdated])
    {
        if (outdated.count) {
            @synchronized(_subtitles) {
                [_subtitles removeObjectsInArray:outdated];
            }
        }
        
        if (!actual.count)
        {
            for (UILabel *label in _Nssubtitleslabel) {
                label.text =NULL;
            }
        }
        else
        {
            NSMutableArray *ms = [NSMutableArray array];
            for (MoboSubtitleFrame *subtitle in actual.reverseObjectEnumerator)
            {
                if (subtitle.text.length!=0)
                [ms addObject:subtitle.text];
            }
            if (!_subtitleString) {
                _subtitleString = [NSMutableArray array];
            }
            if (![_subtitleString isEqualToArray:ms]) {
                _subtitleString =[ms copy] ;
                for (int n =0; n<_subtitleString.count;n++) {
//                    NSLog(@"_subtitleString.count %lu  _Nssubtitleslabel.count%lu",(unsigned long)_subtitleString.count,(unsigned long)_Nssubtitleslabel.count);
                    UILabel * _subtitlesLabel = _Nssubtitleslabel[n];
                    _subtitlesLabel.text = _subtitleString[n];
                    _subtitlesLabel.textColor =_SubtitleTextColor;
                    _subtitlesLabel.shadowColor = _SubtitleisShadow;
                    _subtitlesLabel.shadowOffset =CGSizeMake(1.0, 1.0);
                    if(_issubtitletextbold)
                    [_subtitlesLabel setFont:[UIFont boldSystemFontOfSize:_SubtitleFontSize]];
                    else
                    [_subtitlesLabel setFont:[UIFont systemFontOfSize:_SubtitleFontSize]];
                    _subtitlesLabel.hidden = NO;
                }
            }
        }
    }
}

- (BOOL) subtitleForPosition: (CGFloat) position
                      actual: (NSArray **) pActual
                    outdated: (NSArray **) pOutdated
{

    
    NSMutableArray *actual = nil;
    NSMutableArray *outdated = nil;
    
    for (SubtitleDataClass * data in _decoder.SubtitleStreamCodecMangeArray) {
        if (data.is_seaching&&data.is_decoding) {

            for (MoboSubtitleFrame *subtitle in data.avsubtitlearry) {
                if (position < subtitle.position) {
                    
                    break; // assume what subtitles sorted by position
                    
                } else if (position >= (subtitle.position + subtitle.duration)) {
                    
                    if (pOutdated) {
                        if (!outdated)
                            outdated = [NSMutableArray array];
                        [outdated addObject:subtitle];
                    }
                    
                } else {
                    
                    if (pActual) {
                        if (!actual)
                            actual = [NSMutableArray array];
                        [actual addObject:subtitle];
                    }
                }
            }
        }
    }
    
//    if (!_subtitles.count)
//        return NO;
    
    for (MoboSubtitleFrame *subtitle in _subtitles) {
        
        if (position < subtitle.position) {
            
            break; // assume what subtitles sorted by position
            
        } else if (position >= (subtitle.position + subtitle.duration)) {
            
            if (pOutdated) {
                if (!outdated)
                    outdated = [NSMutableArray array];
                [outdated addObject:subtitle];
            }
            
        } else {
            
            if (pActual) {
                if (!actual)
                    actual = [NSMutableArray array];
                [actual addObject:subtitle];
            }
        }
    }


//    for (MoboSubtitleFrame *subtitle in ) {
//        <#statements#>
//    }
    
    if (pActual) *pActual = actual;
    if (pOutdated) *pOutdated = outdated;
    
    return actual.count || outdated.count;
}



- (void) fullscreenMode: (BOOL) on
{
    _fullscreen = on;
}

- (void) setMoviePositionFromDecoder
{
    _moviePosition = _decoder.position;
}

- (void) setDecoderPosition: (CGFloat) position
{

    _decoder.position = position;
}



- (void) updatePosition: (CGFloat) position
               playMode: (BOOL) playMode
{
    [self freeBufferedFrames];
    
    position = MIN(_decoder.duration , MAX(0, position));
    
    __weak MoboSoftViewController *weakSelf = self;

    dispatch_async(_dispatchQueue, ^{
        
        if (playMode)
        {
        
            {
                __strong MoboSoftViewController *strongSelf = weakSelf;
                if (!strongSelf) return;
                [strongSelf setDecoderPosition: position];
            }
            
            dispatch_async(dispatch_get_main_queue(), ^{
        
                __strong MoboSoftViewController *strongSelf = weakSelf;
                if (strongSelf)
                {
                    [strongSelf setMoviePositionFromDecoder];
                    [strongSelf play];
                }
            });
            
        } else
        {

            {
                __strong MoboSoftViewController *strongSelf = weakSelf;
                if (!strongSelf) return;
                [strongSelf setDecoderPosition: position];
                [strongSelf decodeFrames];
            }
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                __strong MoboSoftViewController *strongSelf = weakSelf;
                if (strongSelf) {
                    [strongSelf setMoviePositionFromDecoder];
                    [strongSelf presentFrame];
                }
            });
        }        
    });
}
-(void) setMoboScalingMode:(NSInteger) moboscalingtype
                 Numerator:(NSInteger) Numerator
               Denominator:(NSInteger) Denominator

{
    UIScreen *screen = [UIScreen mainScreen];
    CGRect fullScreenRect = screen.bounds;
    UIView *frameView = [self frameView];
    switch (moboscalingtype) {
        case MoboPlayerScalingModeFit:
            frameView.frame =fullScreenRect;
            frameView.contentMode = UIViewContentModeScaleAspectFit;
            break;
        case MoboPlayerScalingModeFill:
            
            if (Numerator == 0 || Denominator == 0) {
                frameView.frame =fullScreenRect;
            }
            else
            {
                CGRect currentrect;
                if (fullScreenRect.size.width/fullScreenRect.size.height -Numerator/Denominator >0.00001) {
                    
                    currentrect.size.height =fullScreenRect.size.height;
                    currentrect.size.width =fullScreenRect.size.height *Numerator/Denominator;
                }
                else
                {
                    currentrect.size.width =fullScreenRect.size.width;
                    currentrect.size.height =fullScreenRect.size.width/(Numerator/Denominator);
                }
                frameView.frame =currentrect;
                frameView.center =self.view.center;
            }
            
            frameView.contentMode =UIViewContentModeScaleToFill;
            break;
        case MoboPlayerScalingModeailor:
            frameView.frame =fullScreenRect;
            frameView.contentMode =UIViewContentModeScaleAspectFill;
            break;
        default:
            break;
    }
    
//    frameView.frame = CGRectMake(0, 0, 100, 200);
//    frameView.frame.size.width =500.00;
    
//    CGRect frame = [self getScreenFrameForCurrentOrientation];
//    frameView.frame = frame;
    NSLog(@"frame view  today size :  %.4f %.4f   d:%d  n:%d  ",frameView.frame.size.width,frameView.frame.size.height,Numerator,Denominator);

    //    frameView.center =self.view.center;
    
    //setmode
    
}
//- (CGRect)getScreenFrameForCurrentOrientation {
//    return [self getScreenFrameForOrientation:[UIApplication sharedApplication].statusBarOrientation];
//}
//
//- (CGRect)getScreenFrameForOrientation:(UIInterfaceOrientation)orientation {
//    
//    UIScreen *screen = [UIScreen mainScreen];
//    CGRect fullScreenRect = screen.bounds;
//    //  BOOL statusBarHidden = [UIApplication sharedApplication].statusBarHidden;
//    
//    //    implicitly in Portrait orientation.
//    if(orientation == UIInterfaceOrientationLandscapeRight || orientation == UIInterfaceOrientationLandscapeLeft){
//        CGRect temp = CGRectZero;
//        temp.size.width = fullScreenRect.size.width;
//        temp.size.height = fullScreenRect.size.height;
//        fullScreenRect = temp;
//    } else if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
//        
//        CGRect temp = CGRectZero;
//        temp.size.width = fullScreenRect.size.height ;
//        temp.size.height =fullScreenRect.size.width;
//        fullScreenRect = temp;
//    }
//    return fullScreenRect;
//}


- (void) freeBufferedFrames
{
    @synchronized(_videoFrames) {
        [_videoFrames removeAllObjects];
    }
    
    @synchronized(_audioFrames) {
        
        [_audioFrames removeAllObjects];
        _currentAudioFrame = nil;
    }
    
    if (_subtitles) {
        @synchronized(_subtitles) {
            [_subtitles removeAllObjects];
        }
    }
    
    _bufferedDuration = 0;
}


- (void) handleDecoderMovieError: (NSError *) error
{
//    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Failure", nil) message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert];
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Failure", nil)
                                                        message:[error localizedDescription]
                                                       delegate:nil
                                              cancelButtonTitle:NSLocalizedString(@"Close", nil)
                                              otherButtonTitles:nil];

    [alertView show];
}

- (BOOL) interruptDecoder
{
    //if (!_decoder)
    //    return NO;
    return _interrupted;
}

@end

